package Analizer;
/**
 * 
 */

import java.awt.AWTException;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Random;
import java.util.TreeMap;
import java.util.Vector;

import Root.DO_Start_AObrazek;



/**
 * @author tom
 * I Mouse Move 
 * pobiera ruch
 * sklauje wzor do wytycznych 
 * @param iEndPointX Y2 - (cel mousa)
 * obraca wzor
 * skaluje czas
 *  
 * @param T1 do T2 - czas w jakm ma dotrzec do celu
 * WartoscSkali Wartosc o ktora nalezy skalowac wyniki
 * @param i_centerX x os obrotu
 * @param i_centerY y os obrotu
 */
public class MouseMove_TM {
	
	private Vector <iElement> iVSchemList = new Vector <iElement>(); // lista schematow
	private TreeMap <Integer, iDANE> iVSchem; // 2 lista
	
	private Random rnd=new Random();
	private Rectangle _FullSizesAllDewicesScreen;
	private Robot rob;
	DO_Start_AObrazek s;
	private boolean play;// jesli true to moze wykonywac dalej dzialanie - referncja do globvalnej play


	
	public MouseMove_TM(String folder, Rectangle _FullSizesAllDewicesScreen){
		try {
			rob = new Robot();
		} catch (AWTException e1) {
			e1.printStackTrace();
		}
		
		ArrayList<iDANE> d = iLadujZPlikuSchemat(folder);
		
		iVSchem = new TreeMap<Integer, iDANE>();
		for (iDANE a : d){
			iVSchem.put((int) a.iDlugoscKrzywej, a);
		}
		
		 /*GraphicsDevice devices[];

		  devices = GraphicsEnvironment.
		     getLocalGraphicsEnvironment().
		     getScreenDevices();

		 int a = Arrays.
		     asList(devices).
		     stream().
		     map(device -> device.getDefaultConfiguration()).
		     map(configuration -> configuration.getBounds()).
		     mapToInt(bounds -> bounds.x + bounds.width).
		     max().
		     orElse(0);*/
		  this._FullSizesAllDewicesScreen = _FullSizesAllDewicesScreen;
		}
	
	
	
	public MouseMove_TM(Vector<iElement> iVSchemList2) {
		// TODO Auto-generated constructor stub
	}



	public MouseMove_TM(String folder, Rectangle _FullSizesAllDewicesScreen,
			DO_Start_AObrazek DO_Start_AObrazek) {
		try {
			rob = new Robot();
		ArrayList<iDANE> d = iLadujZPlikuSchemat(folder);
		iVSchem = new TreeMap<Integer, iDANE>();
		for (iDANE a : d){
			iVSchem.put((int) a.iDlugoscKrzywej, a);
		}
		} catch (AWTException e1) {
			e1.printStackTrace();
		}
		this._FullSizesAllDewicesScreen = _FullSizesAllDewicesScreen;
		this.s = DO_Start_AObrazek;
	}



	public ArrayList<iDANE> iLadujZPlikuSchemat(String folder){

		System.out.println("ODCZYTUJE SCHEMATY: \n" + folder);


		ArrayList<iDANE> id = null;
		ObjectInputStream in;
		
		    String fileName = "SCHEMATY.csv";
		    try{
		    in = new ObjectInputStream(new FileInputStream(folder+fileName));
		    }catch(IOException e){
		    	return null;
		    }

		    try{
		    id =  (ArrayList<iDANE>) in.readObject();
		    }catch(IOException | ClassNotFoundException e){
		    	
		      e.printStackTrace();
		      return null;
		    } finally {
		    try {
				in.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		    }
		
		
		
		//System.out.println("Dane size " + id.size());
		//System.out.println(id.get(1).iCzasKrzywej);
		
		return id;
	}
	
	//========================	==============================================

	/**
	 * @param iTabZrodlo
	 * @param Xs
	 * @param Ys
	 * @param Xe
	 * @param Ye
	 * @param iCzasZrodlo
	 * @param iCzasCel
	 * @return
	 */
	public double[][] iTransformuj(int [][] iTabZrodlo, int Xs, int Ys, int Xe, int Ye, double iCzasZrodlo, double iCzasCel){
		boolean Diagnostyka4 = false;
		
//		System.out.println("STRT+++++++++++++++++++++ ");
		boolean iOWektor = true;
		boolean iOSkale = true;
		boolean iOObrot = true;
		double start = System.currentTimeMillis();
		double[][] iTabTmp = new double [iTabZrodlo.length][3];
		
		///=======Zrodlo========
		int iX1 = iTabZrodlo [0][0]; 															//Punkt obrotu (1 punkt tablicy)
		int iY1 = iTabZrodlo [0][1];
		int iX2 = iTabZrodlo [iTabZrodlo.length-1][0];												//koniec krzywej
		int iY2 = iTabZrodlo [iTabZrodlo.length-1][1];

		///=======CEL========
		Xs = Xs; 													//Punkt obrotu (1 punkt tablicy)
		Ys = Ys;
		Xe = Xe;																	//koniec krzywej
		Ye = Ye;

		
		///=======Kopia tablicy========
		for(int x=0; x<iTabZrodlo.length; x++){
			iTabTmp[x][0] = (iTabZrodlo[x][0]);
			iTabTmp[x][1] = (iTabZrodlo[x][1]);
			iTabTmp[x][2] = iTabZrodlo[x][2];
			//System.out.println("W X:"+ iTabRuch[x][0] + " Y:" + iTabRuch[x][1] + " CZAS: " + iTabRuch[x][2]);
		}
		
		///=======Obroc========
		double iKatZrodla = iObliczKatObrotu(iTabTmp[0][0], iTabTmp[0][1], iTabTmp[iTabTmp.length-1][0], iTabTmp[iTabTmp.length-1][1]);
//		System.out.println("kat Zrodla " + iKatZrodla + "\n");
		
		double iKatCelu = iObliczKatObrotu(Xs, Ys, Xe, Ye);
//		System.out.println("kat Celu " +  iKatCelu + "\n");
		
		///=======Finalne========
		double iKatFinal = iKatCelu-iKatZrodla;
//		System.out.println("kat Final " + iKatFinal + "\n");
		
		
		///=======Przesun o wektor========
//		System.out.println(igetCurrentPosX()+" "+igetCurrentPosY());
		double iwektorX = (igetCurrentPosX()-iTabZrodlo [0][0]);
		double iwektorY = (igetCurrentPosY()-iTabZrodlo [0][1]);
//		System.out.println("XZstart:" + iTabTmp [0][0] + " YZs:" + iTabTmp [0][1] + " XCs:"+ Xs + " YCs:" + Ys );
//		System.out.println("XZeend :" + iTabTmp [iTabTmp.length-1][0] + " YZe:" + iTabTmp [iTabTmp.length-1][1] + " XCe:"+ Xe + " YCe:" + Ye );

		//System.out.println("Przesun o Wektor X:" + iwektorX + " Przesun o Y:" + iwektorY+"\n");

		for(int x=0; iOWektor && x<iTabZrodlo.length; x++){
			iTabTmp[x][0] = (iTabZrodlo[x][0]+iwektorX);
			iTabTmp[x][1] = (iTabZrodlo[x][1]+iwektorY);
			iTabTmp[x][2] = iTabZrodlo[x][2];
			//System.out.println("W X:"+ iTabRuch[x][0] + " Y:" + iTabRuch[x][1] + " CZAS: " + iTabRuch[x][2]);
		}
		
		///=======Obrot========
		for(int x=0; iOObrot && x < iTabTmp.length; x++){
			iTabTmp[x][0] = i_ObliczObrotX(iTabTmp[0][0], iTabTmp[0][1], iTabTmp[x][0], iTabTmp[x][1], iKatFinal);
			iTabTmp[x][1] = i_ObliczObrotY(iTabTmp[0][0], iTabTmp[0][1], iTabTmp[x][0], iTabTmp[x][1], iKatFinal);
		}
		
		///=======Skaluj========
		double iSkalaX = 0, iSkalaY = 0;
		double iSkalaCzasu;
		if (iCzasCel > 0) iSkalaCzasu = iCzasCel/iCzasZrodlo;
		else iSkalaCzasu = 1;
		
		double odcinekZrodloX = (iTabTmp[0][0]-iTabTmp[iTabTmp.length-1][0]);
		double odcinekZrodloY = (iTabTmp[0][1]-iTabTmp[iTabTmp.length-1][1]);

		double odcinekCelX = (Xs-Xe);
		double odcinekCelY = (Ys-Ye);
		
		if (odcinekZrodloX==0 | odcinekCelX == 0){
			iSkalaX = 1;
			System.err.println(" X ZERO");
		}else iSkalaX = (odcinekCelX / odcinekZrodloX);


		if (odcinekZrodloY == 0 | odcinekCelY == 0){
			iSkalaY = 1;
			System.err.println(" Y ZERO");
		} else iSkalaY = odcinekCelY / odcinekZrodloY;


//		System.out.println("Skala X-ow: " + iSkalaX);
//		System.out.println("Skala Y-ow: " + iSkalaY);
//		System.out.println("Skala CZasu: " + iSkalaCzasu + "\n");

		double xs=0, ys=0;
		for(int x=0; iOSkale && x<iTabTmp.length; x++){
			xs=iTabTmp[0][0]+ ((iTabTmp[x][0]-iTabTmp[0][0])*iSkalaX);
			ys=iTabTmp[0][1]+ ((iTabTmp[x][1]-iTabTmp[0][1])*iSkalaY);
			//sprawdzenie zeby nie wychodzilo poza okno
			
			if(xs<=_FullSizesAllDewicesScreen.x) {
					if (Diagnostyka4)System.err.println(" kursor X<: " + xs);
				xs=_FullSizesAllDewicesScreen.x + Math.abs((_FullSizesAllDewicesScreen.x-_FullSizesAllDewicesScreen.x)/2);
					if (Diagnostyka4)System.err.println(" kursor X<//korekta: " + xs);

			}
			if(xs>=_FullSizesAllDewicesScreen.width) {
					if (Diagnostyka4)System.err.println(" kursor X>: " + xs);
				xs=_FullSizesAllDewicesScreen.width - Math.abs(_FullSizesAllDewicesScreen.width-(_FullSizesAllDewicesScreen.x+_FullSizesAllDewicesScreen.width))/2;
					if (Diagnostyka4)System.err.println(" kursor X>//korekta: " + xs);

			}
			if(ys<=_FullSizesAllDewicesScreen.y) {
					if (Diagnostyka4)System.err.println(" kursor Y<: " + ys);
				ys=_FullSizesAllDewicesScreen.y + Math.abs((_FullSizesAllDewicesScreen.y-_FullSizesAllDewicesScreen.y)/2);
					if (Diagnostyka4)System.err.println(" kursor Y<//korekta: " + ys);

			}
			if(ys>=_FullSizesAllDewicesScreen.height) {
					if (Diagnostyka4)System.err.println(" kursor Y>: " + ys);
				ys=_FullSizesAllDewicesScreen.height-Math.abs(_FullSizesAllDewicesScreen.height-(_FullSizesAllDewicesScreen.y+_FullSizesAllDewicesScreen.height))/2;
					if (Diagnostyka4)System.err.println(" kursor Y>//korekta: " + ys);
			}
			
			iTabTmp[x][0] = xs;
			iTabTmp[x][1] = ys;
			iTabTmp[x][2] *= iSkalaCzasu;
		}


		///=======Korekta========
		
//		System.out.println("CZAS YKONANIA PROGRAMU MOUSE MOVE " + (System.currentTimeMillis()-start)/1000);
//		System.out.println("\nSTOP+++++++++++++++++++++ ");
		return iTabTmp;
		}
 
	
	/**
	 * @param tab
	 * @return
	 * prezuwa mysz
	 */
	private boolean iPrzesunMysz(double tab[][]){
		double start = System.currentTimeMillis();
		for (int a=0;  a<tab.length; a++){
//			System.out.println("KONIEC X:"+ (int)tab[x][0] + " Y:" + (int)tab[x][1] + " CZAS: " + (int)tab[x][2]);
			int x = (int) tab[a][0];
			int y = (int) tab[a][1];
			int z = (int) tab[a][2];
			if (s.is_play() && x>0 | y>0){
				rob.mouseMove(x, y);
				rob.delay(z);
			} 
		}
//		System.out.println("CZAS YKONANIA PROGRAMU MOUSE MOVE " + (System.currentTimeMillis()-start));
		return true;
	}
	
	private boolean iKliknijMyszka(){
		if (this.s.is_play())
		{
		rob.delay(int_RandomMinMax(300, 600));
		rob.mousePress(InputEvent.BUTTON1_MASK);
		rob.delay(int_RandomMinMax(50, 150));
		rob.mouseRelease(InputEvent.BUTTON1_MASK);
		return true;
		} else return false;
		
	}
	
	private double iObliczKatObrotu (double iTabRuch, double iTabRuch2, double iTabRuch3, double iTabRuch4){
		double tmpX = iTabRuch3-iTabRuch;
		double tmpY = iTabRuch4-iTabRuch2;
		double tmp = Math.abs(Math.hypot(tmpX , tmpY));
		double wsp  = 2*Math.PI;
		double wyn = 0;
		
		if (tmpX>=0 & tmpY>=0){
			wyn = Math.asin(tmpY/tmp);
//			System.out.println("STOPNIE 1: " + wyn);
		}
		if (tmpX<0 & tmpY>=0){
			//wyn = 2*(Math.PI/2)-Math.asin(tmpY/tmp);
			wyn = Math.PI/2-Math.asin(tmpY/tmp);
//			System.out.println("STOPNIE 2: " + wyn);
			
		}
		if (tmpX<0 & tmpY<0){
			//wyn = 2*(Math.PI/2)+( Math.asin((Math.abs(tmpY))/tmp) );
			wyn = Math.PI+( Math.asin((Math.abs(tmpY))/tmp) );
//			System.out.println("STOPNIE 3: " + wyn);
		}
		if (tmpX>=0 & tmpY<0){
			//wyn = 4*(Math.PI/2)-( Math.asin((Math.abs(tmpY))/tmp) );
			wyn = (Math.PI*2)-( Math.asin((Math.abs(tmpY))/tmp) );
//			System.out.println("STOPNIE 4: " + wyn);
		}
		//System.out.println("WYNIK KAT: " + ((wyn)*(180/Math.PI)));
		// RADIANY NA SIN http://www.fizykon.org/rpo/radian_rpo.htm
		//http://matematyka.pisz.pl/forum/54154.html
		//return 2*Math.PI*(Math.toDegrees((2*Math.PI*wyn)/360));
		if (wyn<0 ) System.err.println("MNIEJSZE OD ZERA");

		return Math.toDegrees(wyn);
	}

	
	private double iObliczDlOdcinka(double iX1, double iY1, double iX2, double iY2){
		return Math.hypot(iX2-iX1, iY2-iY1);
	}
	private int[] igetCurrentPosition(){
		PointerInfo pointer = MouseInfo.getPointerInfo();
		return new int[]{pointer.getLocation().x, pointer.getLocation().y};
	}
	private int igetCurrentPosX(){
		//System.out.print("POZYCJA MOUSA X: " + pointer.getLocation().x + " ");
		PointerInfo pointer = MouseInfo.getPointerInfo();
		return pointer.getLocation().x;
	}
	private int igetCurrentPosY(){
		//System.out.println("POZYCJA MOUSA Y: " + pointer.getLocation().y);
		PointerInfo pointer = MouseInfo.getPointerInfo();
		return pointer.getLocation().y;
	}
	//========================================================================

	private double i_ObliczObrotX(double iX1, double iY1, double iX2, double iY2, double iKatObrotu){
		iKatObrotu = Math.toRadians(iKatObrotu);
		return iX1 + (iX2-iX1)*Math.cos(iKatObrotu) - (iY2-iY1)*Math.sin(iKatObrotu);
	}
	private double i_ObliczObrotY(double iX1, double iY1, double iX2, double iY2, double iKatObrotu){
		iKatObrotu = Math.toRadians(iKatObrotu);
		return  iY1 + (iX2-iX1)*Math.sin(iKatObrotu) + (iY2-iY1)*Math.cos(iKatObrotu);
	}
	
	public static int int_RandomMinMax(int Min, int Max){

		return (Min + (int) (Math.random() * (Max - Min)));
	}

	//========================================================================
	
	/**

	 * @param Xe X end
	 * @param Ye Y end
	 * @param iPozycjaListySchem
	 * @param iT2 czas ruchu
	 */
	public void iMouseMove (int Xe, int Ye, double iT2, boolean clic){
			int odcinek =(int) Math.hypot( Math.abs (igetCurrentPosX() - Xe),(Math.abs (igetCurrentPosY() - Ye)) );
			iDANE iEl = iVSchem.ceilingEntry(odcinek).getValue();
			iPrzesunMysz(iTransformuj((iEl.iKrzywa), igetCurrentPosX(), igetCurrentPosY(), Xe, Ye, iEl.iCzasKrzywej, iT2));
			if (clic) iKliknijMyszka();
		
		
		}
	public void iMouseMoveRND (Rectangle obszarRuchuRnd, boolean clic){
		if (obszarRuchuRnd != null){
			int Xe = int_RandomMinMax(obszarRuchuRnd.x, obszarRuchuRnd.x + obszarRuchuRnd.width);
			int Ye = int_RandomMinMax(obszarRuchuRnd.y, obszarRuchuRnd.y + obszarRuchuRnd.height);
			int iT2 = int_RandomMinMax(800, 1500);
			int odcinek =(int) Math.hypot( Math.abs (igetCurrentPosX() - Xe),(Math.abs (igetCurrentPosY() - Ye)) );
			iDANE iEl = iVSchem.ceilingEntry(odcinek).getValue();
			iPrzesunMysz(iTransformuj((iEl.iKrzywa), igetCurrentPosX(), igetCurrentPosY(), Xe, Ye, iEl.iCzasKrzywej, iT2));
			if (clic) iKliknijMyszka();
		}
		
		}

}